package net.stogi.unicore.beyond.api.model;

import java.util.ArrayList;
import java.util.List;

import net.stogi.unicore.beyond.api.exception.InputDefinitionAlreadyExistsException;

public class InputGroup extends Entity {

	private static final long serialVersionUID = 7381003090104857466L;

	private int index;

	private List<InputDefinition> inputDefinitions;
	
	private String name;
	
	private TaskDefinition taskDefinition;

	public InputGroup() {
		inputDefinitions = new ArrayList<InputDefinition>();
	}
	
	public InputGroup(String name) {
		this();
		this.name = name;
	}
	
	public InputDefinition addInputDefinition(InputDefinition inputDefinition) {
		inputDefinition.setIndex(inputDefinitions.size());
		inputDefinitions.add(inputDefinition);
		inputDefinition.setInputGroup(this);
		return inputDefinition;
	}
	
	public InputDefinition addInputDefinition(String name, InputType inputType) throws InputDefinitionAlreadyExistsException {
		assert name != null;
		assert inputType != null;
		if (containsInputDefinitionWithName(name)) {
			throw new InputDefinitionAlreadyExistsException(name);
		}
		InputDefinition inputDefinition = new InputDefinition(name, inputType);
		return addInputDefinition(inputDefinition);
	}

	public boolean containsInputDefinitionWithName(String name) {
		assert name != null;
		int count = 0;
		for (InputDefinition inputDefinition : inputDefinitions) {
			if (name.equals(inputDefinition.getName())) {
				count++;
			}
		}
		if (count == 0) {
			return false;
		}
		return true;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (!(obj instanceof InputGroup)) {
			return false;
		}
		InputGroup other = (InputGroup) obj;
		// Check name.
		if (name == null) {
			if (other.name != null) {
				return false;
			}
		}
		else if (!name.equals(other.name)) {
			return false;
		}
		return true;
	}

	public int getIndex() {
		return index;
	}

	public InputDefinition getInputDefinition(int index) {
		return inputDefinitions.get(index);
	}

	public List<InputDefinition> getInputDefinitions() {
		return inputDefinitions;
	}

	public String getName() {
		return name;
	}

	public TaskDefinition getTaskDefinition() {
		return taskDefinition;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	
	public boolean moveInputDefinition(InputDefinition inputDefinition, int offset) {
		assert inputDefinition != null;
		final int index = inputDefinition.getIndex();
		final int newIndex = index + offset;
		if (newIndex < 0 || newIndex >= inputDefinitions.size()) {
			// TODO: Maybe exception ?
			return false;
		}
		inputDefinitions.remove(index);
		inputDefinitions.add(newIndex, inputDefinition);
		final int start, end;
		if (newIndex < index) {
			start = newIndex;
			end = index;
		}
		else {
			start = index;
			end = newIndex;
		}
		for (int i = start; i <= end; i++) {
			inputDefinitions.get(i).setIndex(i);
		}
		return true;
	}
	
	public boolean removeInputDefinition(InputDefinition inputDefinition) {
		assert inputDefinition != null;
		boolean removed = false;
		final int removedIndex = inputDefinition.getIndex();
		if (inputDefinitions.remove(inputDefinition)) {
			removed = true;
			for (int index = removedIndex; index < inputDefinitions.size(); index++) {
				inputDefinitions.get(index).setIndex(index);
			}
			inputDefinition.setInputGroup(null);
		}
		return removed;
	}

	public InputDefinition selectInputDefinitionByName(String name) {
		assert name != null;
		InputDefinition selectedInputDefinition = null;
		for (InputDefinition inputDefinition : inputDefinitions) {
			if (name.equals(inputDefinition.getName())) {
				selectedInputDefinition = inputDefinition;
				break;
			}
		}
		return selectedInputDefinition;
	}

	public InputDefinition selectInputDefinitionWithId(Long id) {
		if (id == null) {
			throw new IllegalArgumentException("Parameter 'id' can't be null");
		}
		InputDefinition selectedInputDefinition = null;
		for (InputDefinition inputDefinition : inputDefinitions) {
			if (id.equals(inputDefinition.getId())) {
				selectedInputDefinition = inputDefinition;
				break;
			}
		}
		return selectedInputDefinition;
	}

	public void setIndex(int index) {
		this.index = index;
	}

	public void setInputDefinitions(List<InputDefinition> inputDefinitions) {
		this.inputDefinitions = inputDefinitions;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setTaskDefinition(TaskDefinition taskDefinition) {
		this.taskDefinition = taskDefinition;
	}
}
